﻿using SD.Common;
using SD.Infrastructure.EntityBase;
using SD.Toolkits.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using SlamDunk.ValueObjects.Enums;
using SlamDunk.ValueObjects.Structs;

namespace SlamDunk.MES.Domain.Entities.DefinitionContext
{
    /// <summary>
    /// 工艺段
    /// </summary>
    [Serializable]
    public class ProcessSegment : PlainEntity, INumerable, INameable, ISortable
    {
        #region # 构造器

        #region 00.无参构造器
        /// <summary>
        /// 无参构造器
        /// </summary>
        protected ProcessSegment()
        {
            //初始化导航属性
            this.PersonRules = new HashSet<SegmentPersonRule>();
            this.EquipmentRules = new HashSet<SegmentEquipmentRule>();
            this.MaterialRules = new HashSet<SegmentMaterialRule>();
            this.ParameterRules = new HashSet<SegmentParameterRule>();
        }
        #endregion

        #region 01.创建工艺段构造器
        /// <summary>
        /// 创建工艺段构造器
        /// </summary>
        /// <param name="segmentNo">工艺段编号</param>
        /// <param name="segmentName">工艺段名称</param>
        /// <param name="durationQuota">工时定额</param>
        /// <param name="directivePath">工艺指导书</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="workStationId">工位Id</param>
        /// <param name="formMode">表单模式</param>
        /// <param name="formDefinition">表单定义</param>
        /// <param name="needToInspect">是否需质检</param>
        /// <param name="sort">排序</param>
        /// <param name="description">描述</param>
        public ProcessSegment(string segmentNo, string segmentName, TimeSpan durationQuota, string directivePath, Guid? facilityId, Guid? workStationId, FormMode formMode, FormDefinition formDefinition, bool needToInspect, int sort, string description)
            : this()
        {
            this.Number = segmentNo;
            this.Name = segmentName;
            this.DurationQuotaTicks = durationQuota.Ticks;
            this.DirectivePath = directivePath;
            this.FacilityId = facilityId;
            this.WorkStationId = workStationId;
            this.FormMode = formMode;
            this.FormDefinitionStr = formDefinition?.ToJson();
            this.NeedToInspect = needToInspect;
            this.Sort = sort;
            this.Description = description;
        }
        #endregion

        #endregion

        #region # 属性

        #region 工艺段编号 —— string Number
        /// <summary>
        /// 工艺段编号
        /// </summary>
        public string Number { get; private set; }
        #endregion

        #region 工艺段名称 —— string Name
        /// <summary>
        /// 工艺段名称
        /// </summary>
        public string Name { get; private set; }
        #endregion

        #region 工时定额 —— TimeSpan DurationQuota
        /// <summary>
        /// 工时定额
        /// </summary>
        public long DurationQuotaTicks { get; private set; }


        /// <summary>
        /// 工时定额
        /// </summary>
        public TimeSpan DurationQuota
        {
            get => TimeSpan.FromTicks(this.DurationQuotaTicks);
        }
        #endregion

        #region 工艺指导书 —— string DirectivePath
        /// <summary>
        /// 工艺指导书
        /// </summary>
        /// <remarks>PDF路径</remarks>
        public string DirectivePath { get; private set; }
        #endregion

        #region 工厂模型Id —— Guid? FacilityId 
        /// <summary>
        /// 工厂模型Id
        /// </summary>
        public Guid? FacilityId { get; private set; }
        #endregion

        #region 工位Id —— Guid? WorkStationId 
        /// <summary>
        /// 工位Id
        /// </summary>
        public Guid? WorkStationId { get; private set; }
        #endregion

        #region 表单模式 —— FormMode FormMode
        /// <summary>
        /// 表单模式
        /// </summary>
        public FormMode FormMode { get; private set; }
        #endregion

        #region 表单定义 —— FormDefinition FormDefinition
        /// <summary>
        /// 只读属性 - 表单定义
        /// </summary>
        public FormDefinition FormDefinition
        {
            get
            {
                return string.IsNullOrWhiteSpace(this.FormDefinitionStr)
                    ? null
                    : this.FormDefinitionStr.AsJsonTo<FormDefinition>();
            }
        }

        /// <summary>
        /// 内部属性 - 表单定义
        /// </summary>
        public string FormDefinitionStr { get; private set; }
        #endregion

        #region 是否需质检 —— bool NeedToInspect
        /// <summary>
        /// 是否需质检
        /// </summary>
        public bool NeedToInspect { get; private set; }
        #endregion

        #region 排序 —— int Sort
        /// <summary>
        /// 排序
        /// </summary>
        public int Sort { get; private set; }
        #endregion

        #region 描述 —— string Description
        /// <summary>
        /// 描述
        /// </summary>
        public string Description { get; private set; }
        #endregion

        #region 导航属性 - 工艺 —— Process Process
        /// <summary>
        /// 导航属性 - 工艺
        /// </summary>
        public virtual Process Process { get; internal set; }
        #endregion

        #region 导航属性 - 人员规范集 —— ICollection<SegmentPersonRule> PersonRules
        /// <summary>
        /// 导航属性 - 人员规范集
        /// </summary>
        public virtual ICollection<SegmentPersonRule> PersonRules { get; private set; }
        #endregion

        #region 导航属性 - 设备规范集 —— ICollection<SegmentEquipmentRule> EquipmentRules
        /// <summary>
        /// 导航属性 - 设备规范集
        /// </summary>
        public virtual ICollection<SegmentEquipmentRule> EquipmentRules { get; private set; }
        #endregion

        #region 导航属性 - 物料规范集 —— ICollection<SegmentMaterialRule> MaterialRules
        /// <summary>
        /// 导航属性 - 物料规范集
        /// </summary>
        public virtual ICollection<SegmentMaterialRule> MaterialRules { get; private set; }
        #endregion

        #region 导航属性 - 参数规范集 —— ICollection<SegmentParameterRule> ParameterRules
        /// <summary>
        /// 导航属性 - 参数规范集
        /// </summary>
        public virtual ICollection<SegmentParameterRule> ParameterRules { get; private set; }
        #endregion

        #endregion

        #region # 方法

        #region 修改工艺段 —— void UpdateInfo(string segmentNo, string segmentName...
        /// <summary>
        /// 修改工艺段
        /// </summary>
        /// <param name="segmentNo">工艺段编号</param>
        /// <param name="segmentName">工艺段名称</param>
        /// <param name="durationQuota">工时定额</param>
        /// <param name="directivePath">工艺指导书</param>
        /// <param name="facilityId">工厂模型Id</param>
        /// <param name="workStationId">工位Id</param>
        /// <param name="formMode">表单模式</param>
        /// <param name="formDefinition">表单定义</param>
        /// <param name="needToInspect">是否需质检</param>
        /// <param name="sort">排序</param>
        /// <param name="description">描述</param>
        public void UpdateInfo(string segmentNo, string segmentName, TimeSpan durationQuota, string directivePath, Guid? facilityId, Guid? workStationId, FormMode formMode, FormDefinition formDefinition, bool needToInspect, int sort, string description)
        {
            this.Number = segmentNo;
            this.Name = segmentName;
            this.DurationQuotaTicks = durationQuota.Ticks;
            this.DirectivePath = directivePath;
            this.FacilityId = facilityId;
            this.WorkStationId = workStationId;
            this.FormMode = formMode;
            this.FormDefinitionStr = formDefinition?.ToJson();
            this.NeedToInspect = needToInspect;
            this.Sort = sort;
            this.Description = description;
        }
        #endregion

        #region 设置工艺段人员规范 —— void SetPersonRules(IEnumerable<SegmentPersonRule> personRules)
        /// <summary>
        /// 设置工艺段人员规范
        /// </summary>
        /// <param name="personRules">工艺段人员规范集</param>
        public void SetPersonRules(IEnumerable<SegmentPersonRule> personRules)
        {
            personRules = personRules?.ToArray() ?? new SegmentPersonRule[0];

            this.ClearPersonRules();
            if (personRules.Any())
            {
                this.PersonRules.AddRange(personRules);
                foreach (SegmentPersonRule personRule in personRules)
                {
                    personRule.ProcessSegment = this;
                }
            }
        }
        #endregion

        #region 设置工艺段设备规范 —— void SetEquipmentRules(IEnumerable<SegmentEquipmentRule> equipmentRules)
        /// <summary>
        /// 设置工艺段设备规范
        /// </summary>
        /// <param name="equipmentRules">工艺段设备规范集</param>
        public void SetEquipmentRules(IEnumerable<SegmentEquipmentRule> equipmentRules)
        {
            equipmentRules = equipmentRules?.ToArray() ?? new SegmentEquipmentRule[0];

            this.ClearEquipmentRules();
            if (equipmentRules.Any())
            {
                this.EquipmentRules.AddRange(equipmentRules);
                foreach (SegmentEquipmentRule equipmentRule in equipmentRules)
                {
                    equipmentRule.ProcessSegment = this;
                }
            }
        }
        #endregion

        #region 设置工艺段物料规范 —— void SetMaterialRules(IEnumerable<SegmentMaterialRule> materialRules)
        /// <summary>
        /// 设置工艺段物料规范
        /// </summary>
        /// <param name="materialRules">工艺段物料规范集</param>
        public void SetMaterialRules(IEnumerable<SegmentMaterialRule> materialRules)
        {
            materialRules = materialRules?.ToArray() ?? new SegmentMaterialRule[0];

            this.ClearMaterialRules();
            if (materialRules.Any())
            {
                this.MaterialRules.AddRange(materialRules);
                foreach (SegmentMaterialRule materialRule in materialRules)
                {
                    materialRule.ProcessSegment = this;
                }
            }
        }
        #endregion

        #region 设置工艺段人员规范 —— void SetParameterRules(IEnumerable<SegmentParameterRule> parameterRules)
        /// <summary>
        /// 设置工艺段人员规范
        /// </summary>
        /// <param name="parameterRules">工艺段人员规范集</param>
        public void SetParameterRules(IEnumerable<SegmentParameterRule> parameterRules)
        {
            parameterRules = parameterRules?.ToArray() ?? new SegmentParameterRule[0];

            this.ClearParameterRules();
            if (parameterRules.Any())
            {
                this.ParameterRules.AddRange(parameterRules);
                foreach (SegmentParameterRule parameterRule in parameterRules)
                {
                    parameterRule.ProcessSegment = this;
                }
            }
        }
        #endregion

        #region 清空工艺段人员规范 —— void ClearPersonRules()
        /// <summary>
        /// 清空工艺段人员规范
        /// </summary>
        private void ClearPersonRules()
        {
            foreach (SegmentPersonRule personRule in this.PersonRules.ToArray())
            {
                this.PersonRules.Remove(personRule);
            }
        }
        #endregion

        #region 清空工艺段设备规范 —— void ClearEquipmentRules()
        /// <summary>
        /// 清空工艺段设备规范
        /// </summary>
        private void ClearEquipmentRules()
        {
            foreach (SegmentEquipmentRule equipmentRule in this.EquipmentRules.ToArray())
            {
                this.EquipmentRules.Remove(equipmentRule);
            }
        }
        #endregion

        #region 清空工艺段物料规范 —— void ClearMaterialRules()
        /// <summary>
        /// 清空工艺段物料规范
        /// </summary>
        private void ClearMaterialRules()
        {
            foreach (SegmentMaterialRule materialRule in this.MaterialRules.ToArray())
            {
                this.MaterialRules.Remove(materialRule);
            }
        }
        #endregion

        #region 清空工艺段参数规范 —— void ClearParameterRules()
        /// <summary>
        /// 清空工艺段参数规范
        /// </summary>
        private void ClearParameterRules()
        {
            foreach (SegmentParameterRule parameterRule in this.ParameterRules.ToArray())
            {
                this.ParameterRules.Remove(parameterRule);
            }
        }
        #endregion

        #endregion
    }
}
